package utils

/*
1	2	3	4	  5	    6...n	  n+1
10	11	pktype	包长度	 数据    3-n crc
*/

import (
	"encoding/binary"
	"errors"
	"fmt"
)

type BufPack struct {
	buf    []byte
	pktype byte
	l_Pack uint16
	size   uint16
}

func NewBufPack() *BufPack {
	return &BufPack{
		buf:    make([]byte, 2047, 2047),
		size:   0,
		l_Pack: 0,
	}
}

func CRC(buf []byte) byte {
	if len(buf) == 0 {
		return 0
	}

	r := buf[0]

	if len(buf) > 1 {
		for _, v := range buf[1:] {
			r ^= v
		}
	}
	return r
}

/*
*

	可适应: trimble 命令
*/
func Crc_Plus(buf []byte) byte {
	if len(buf) == 0 {
		return 0
	}

	r := buf[0]

	if len(buf) > 1 {
		for _, v := range buf[1:] {
			r += v
		}
	}
	return r
}

func Crc32(buf []byte) uint32 {
	if len(buf) == 0 {
		return 0
	}

	r := uint32(buf[0])

	if len(buf) > 1 {
		for _, v := range buf[1:] {
			r += uint32(v)
		}
	}
	return r
}

func PacakgeBuf(buf []byte, pktype byte) (rval []byte, err error) {
	b := make([]byte, 2)
	pbuf := make([]byte, 0, 2046)

	// 引导字节3
	pbuf = append(pbuf, byte(10))
	pbuf = append(pbuf, byte(11))

	pbuf = append(pbuf, byte(pktype))

	l := len(buf)
	if l > 2040 {
		return nil, errors.New(fmt.Sprintf("buf (len:%d) is too long!(PacakgeBuf)", l))
	}

	// 长度
	binary.BigEndian.PutUint16(b, uint16(l))
	pbuf = append(pbuf, b...)

	// 内容
	pbuf = append(pbuf, buf...)

	// crc
	c := CRC(pbuf[2:])
	pbuf = append(pbuf, c)
	return pbuf, nil
}

func (this *BufPack) Reset() {
	this.size = 0
	this.l_Pack = 0
	this.pktype = 0
}

func (this *BufPack) GetBuf() []byte {
	return this.buf[5 : this.size-1]
}

func (this *BufPack) GetType() byte {
	return this.buf[2]
}

func (this *BufPack) InputBuf(b byte) int {
	if this.size == 0 {
		if b != 10 {
			this.Reset()
			return -1
		}
		this.buf[this.size] = b
		this.size++
		return 0
	} else if this.size == 1 {
		if b != 11 {
			this.Reset()
			return -1
		}
		this.buf[this.size] = b
		this.size++
		return 0
	} else if this.size == 3 {
		this.buf[this.size] = b
		this.size++
		this.pktype = b
		return 0
	} else {
		if this.size >= 2047 {
			Log.Errf("BufPack超出范围(包长度：%d, 当前长度:%d)", this.l_Pack, this.size)
			this.Reset()
			return -3
		}
		this.buf[this.size] = b
		this.size++

		if this.size == 5 {
			this.l_Pack = binary.BigEndian.Uint16(this.buf[3:5])
			if this.l_Pack > 2040 {
				this.Reset()
				return -3
			}
		} else if this.size == this.l_Pack+6 {
			c := CRC(this.buf[2 : this.size-1])
			if c == b {
				return 1
			} else {
				this.Reset()
				return -2
			}
		}

		return 0
	}
}
